LiveData 是一個用於持有數據並可以監聽數據變動的元件,通常搭配 ViewModel 使用。
除此之外,LiveData 還可以感知生命週期,因此觀察者可以指定某一個具有生命週期的元件給 LiveData,例如 Activity, Fragment,並在生命週期是 活躍 的時候進行更新,也就是生命週期裡的 onStart 和           onResume。
除了傳統的觀察者模式中的功能之外,LiveData 還有很多優點:
LiveData 的任何事件的,能讓系統省去不必要的接受事件。LiveData 能夠感知生命週期,所以當 Activity 被銷毀時,LiveData 也會隨之銷毀,避免不必要的引用而造成的內存泄露。LiveData 則會讓應用處在 活躍狀態時 才跳 Toast,能帶來更好的使用者體驗。class MyViewModel : ViewModel() {
    val name = MutableLiveData<String>()
}
只要把 ViewModel 裡面的數據全部改成用 MutableLiveData 包起來就可以了,MutableLiveData 裡面接的是泛型 T,所以可以接受任何的型態。
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activtiy_live_data)
        viewModel = ViewModelProviders.of(this).get(MyViewModel::class.java)
        viewModel.name.observe(this, object : Observer<String> {
            override fun onChanged(name: String) {
                userName.text = name// or do anything you want.
            }
        })
當 viewModel 裡面的變數 name 變動時,就會傳進 onChanged,裡面再去實作數據變更後要做的事情就可以了。
這邊我曾經犯下一個錯誤 特地紀錄一下
我把 LiveData 和 DataBinding 一起使用的時候,因為 DataBinding 的 UI 更新是跟著 ViewModel 內的變數,所以我在 onChanged 裡面去改變 viewModel 裡面的值
  viewModel.name.observe(this, object : Observer<String> {
            override fun onChanged(name: String) {
                viewModel.updateName(name)
            }
        })
這樣會造成什麼問題呢?因為 ViewModel 裡的 name 被改變了,在 View 這邊的 observe 觀察到他的改變,所以又進來 onChanged 這裏,又再把 ViewModel 裡的 name 更新了一次,View 這邊的 observe 又觀察到他的改變....
變成無窮迴圈了!
所以這邊其實可以把 observe 拿掉,讓 DataBinding 去更新,或是把 這個元件在 xml 的 binding 拿掉,然後在 onChanged 做正常的 settext,兩者擇一就可以了。
class MyViewModel : ViewModel() {
    val name = MutableLiveData<String>()
    
    fun updataName(name: String){
    
        this.name.value = name// UI Thread
        this.name.postValue(name)// Worker Thread
    }
}
跟 DataBinding 一樣,在 View 那邊呼叫 updateName 把值丟進來,在 UI Thread 的更新可以直接 setValue,在 Worker Thread 的更新就只能用 postValue。
到這邊為止就算完成了 LiveData 的基本使用,非常的簡單!
如果今天 UI 接回來的 LiveData 不是自己想要的,而是想要做出一些組合,或是要將 LiveData 傳遞給另一個 LiveData,就要用到 Transformations 這個類別。
舉例來說:
有一個 data class User 包在一個 LiveData 裡面
data class User(
    val firstName: String,
    val lastName: String
)
val user = MutableLiveData<User>()
如果我想要有一個 firstName + lastName 的組合,就可以這樣做:
val userFullName = Transformations.map(user) { user ->
    user.firstName + user.lastName
}
大括號內取到這個 User 類別後,裡面的事就跟 LiveData 無關了,就可以去做一些自己想要的操作,操作完後返回的也是一個 LiveData 型別,所以要記得在 View 對這個 userFullName 做 observe 就可以了。
先來看這張圖
MediatorLiveData 是 LiveData 的子類,可以通過 MediatorLiveData 合併多個 LiveData 數據。其中任意一個 LiveData 數據發生變化,MediatorLiveData 都會通知觀察他的對象。
如果今天有一個需求是有很多項資料變動時都要做同一件事,比如說購物車內的任一商品有更動時、或是使用折價券時都要去更新總價,但又不想要在每個觀察事件內寫同樣的程式碼,這時候就可以使用 MediatorLiveData 來合併多個 LiveData。
使用上也很簡單,宣告時的型態是 MediatorLiveData,接著在適當的時機(通常是初始化時)把想要合併的 LiveData 利用 addSource 的方式加進去,並定義好當這個 LiveData 改變時,要做什麼事。
    val name = MutableLiveData<String>()
    val id = MutableLiveData<Int>()
    val mediatorLiveData = MediatorLiveData<String>()
    
fun addSourceToMediatorLiveData() {
        mediatorLiveData.addSource(name) {
            //do something when name changed
        }
        mediatorLiveData.addSource(id) {
            //do something when id changed
        }
    }
addSource 想要合併幾個都可以,記得在 View 觀察這個 mediatorLiveData 對象即可。
LiveData 篇幅不多,使用簡單,主要的功能其實都在跟 ViewModel 搭配的時候包在一起了,當然最大的賣點還是能夠感知生命週期,能夠讓 data 跟著 View 的生命週期在運作,就好像真的活生生的有生命一樣,重新定義了以前對數據類都是靜態的等著被呼叫、賦值的這種想法,使用了 LiveData 後,數據類變的動態,也更貼近了使用者,我想這也是 LiveData 的命名由來吧!
有任何問題或講得不清楚的地方歡迎留言和我討論。
更歡迎留言糾正我任何說錯的地方!
下一篇:Room (一) 介紹與基本使用